# -*- coding: utf-8 -*-
import re
import math
from urlparse import urlsplit
from pkg_resources import resource_filename

from trac.core import Component, implements
from trac.web.api import IRequestHandler, RequestDone
from trac.web.chrome import ITemplateProvider
from trac.web.chrome import Chrome

from multiproject.core.configuration import conf
from multiproject.project import Project
from multiproject.core import db


class GlobalNews(object):
    """
    Class for handling global news data from all news forums
    """

    def __init__(self):
        self.log = conf.log

    def get_global_news(self, limit=0):
        """
        Return latest news from all projects. The data is in form of a list of dicts, containing subject,
        author, time, body of the news, topic id, project, environment name, and icon id.

        :param int limit: Optional limit to limit the results
        :returns: The news, if any
        """
        news = []

        if not limit:
            query = '''
                SELECT subject, author, time, body, topic_id, environment_name
                FROM global_announcements
                ORDER by time DESC
            '''
        else:
            query = '''
                SELECT subject, author, time, body, topic_id, environment_name
                FROM global_announcements
                ORDER by time DESC
                LIMIT %(limit)d
            ''' % {'limit': db.safe_int(limit)}

        with db.admin_query() as cursor:
            try:
                cursor.execute(query)
                for row in cursor:
                    news.append({
                        'subject': (row[0] != "" and row[0] or "No subject"),
                        'author': row[1],
                        'time': row[2],
                        'body': row[3],
                        'topic_id' : row[4],
                        'project': Project.get(env_name=row[5])
                    })
            except Exception:
                self.log.exception("SQL query failed: %s" % query)
                raise

        return news


class GlobalAnnouncementsModule(Component):
    implements(IRequestHandler, ITemplateProvider)

    # IRequestProvider

    def match_request(self, req):
        return re.match(r'/globalannouncements[.xml]?', req.path_info)

    def process_request(self, req):
        if req.path_info.endswith('.xml'):
            return self.show_rss_announcements(req)
        return self.show_html_announcements(req)

    # ITemplateProvider

    def get_templates_dirs(self):
        return [resource_filename(__name__, 'templates')]

    def get_htdocs_dirs(self):
        return []

    def _get_latest_events(self):
        gn = GlobalNews()
        return gn.get_global_news(150)

    # Internal methods: for showing global announcements in different formats

    def show_html_announcements(self, req):
        """
        Returns the HTML output
        """
        data = {'events':self._get_latest_events(),
                'math':math}

        return 'discussion-global-announcement-list.html', data, None

    def show_rss_announcements(self, req):
        try:
            content = self.render_rss(req)
        except Exception as e:
            self.log.exception('Failed to show global announcements: %s' % e)
            return 'error.rss', {'msg':str(e)}, 'application/rss+xml'

        req.send(content, 'application/rss+xml')
        raise RequestDone

    def render_rss(self, req):
        """
        Renders the global announcements in RSS/XML format

        :param req: Trac request
        :raise: Exception in a case of rendering issues
        :return: Rendered RSS string
        """
        data = {'events':self._get_latest_events(),
                'domain':self.config.get('multiproject', 'domain_name'),
                'url_service':urlsplit(req.abs_href.base)[0]+'://'+urlsplit(req.abs_href.base)[1]+'/'}
        chrome = Chrome(self.env)

        output = chrome.render_template(req, "discussion-global-announcement-list.rss", data, 'application/rss+xml')

        return output
